package com.fulihui.usercore.core.processor.vcode;

import com.alibaba.fastjson.JSON;
import com.fulihui.systemcore.condition.PropertiesCondition;
import com.fulihui.systemcore.dto.PropertiesDTO;
import com.fulihui.systemcore.enums.EnvTypeEnum;
import com.fulihui.usercore.common.integration.PropertiesServiceClient;
import com.fulihui.usercore.common.util.Errors;
import com.fulihui.usercore.config.RedisUtil;
import com.fulihui.usercore.enums.VcodeProcessTypeEnum;
import com.fulihui.usercore.request.vcode.VcodeCheckRequest;
import com.fulihui.usercore.request.vcode.VcodeSendRequest;
import org.near.servicesupport.error.InvokeServiceException;
import org.near.toolkit.common.DateUtils;
import org.near.toolkit.common.StringUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;

import java.text.ParseException;
import java.util.Date;
import java.util.List;

import static org.apache.commons.lang3.RandomStringUtils.randomNumeric;

/**
 * @author Created by Willard.Hu on 2016/6/4.
 */
@Component("mobileVcodeProcessor")
public class MobileVcodeProcessor extends AbstractVcodeProcessor {
    private final transient Logger LOG = LoggerFactory.getLogger(getClass());
    /**
     * 手机验证码key前缀，key = KEY_PREFIX: + namespace: + mobileNo
     */
    private static final String KEY_PREFIX = "USER_MOBILE_VCODE:";
    /**
     * 短信公司签名
     */
    private final static String SMS_SIGN = "福礼惠";

    private final static String SMS_VCODE_MSG_KEY = "SMS_VCODE_MSG";

    @Autowired
    private PropertiesServiceClient propertiesServiceClient;
    @Autowired
    private RedisUtil redisUtil;
    @Value("${product.env}")
    private String prodEnv;

    @Override
    public void send(VcodeSendRequest request) {

        String key = KEY_PREFIX + request.getVcodeNamespace() + request.getAccountNo();
        VcodeCache cache;
        String cacheJson = (String) redisUtil.get(key);
        if (StringUtil.isNotBlank(cacheJson)) {
            cache = JSON.parseObject(cacheJson, VcodeCache.class);
            Date gmtCreate = null;
            try {
                gmtCreate = DateUtils.parseLongFormat(cache.getGmtCreate());
            } catch (ParseException parseException) {
                parseException.printStackTrace();
            }
            if (new Date().before(DateUtils.addSeconds(gmtCreate, request.getLimitTime()))) {
                LOG.error("{}在{}秒内不能重复发送，上次发送时间{}", request.getAccountNo(),
                        request.getLimitTime(), cache.getGmtCreate());
                throw new InvokeServiceException(Errors.VCode.CANT_REPEAT_IN_TIME);
            }
        } else {
            cache = new VcodeCache();
        }
        String vcode = randomNumeric(request.getVcodeLength());
        cache.setVcode(vcode);
        cache.setGmtCreate(DateUtils.formatLongFormat(new Date()));


        String tmpmsg = (String) redisUtil.get(SMS_VCODE_MSG_KEY);
        if (StringUtil.isBlank(tmpmsg)) {
            PropertiesCondition condition = new PropertiesCondition();
            condition.setEnvType(prodEnv);
            condition.setProdName("FULIHUI");
            condition.setKey("SMS_VCODE");
            List<PropertiesDTO> list = propertiesServiceClient.query(condition);
            if (!CollectionUtils.isEmpty(list)) {
                tmpmsg = list.get(0).getValue();
                redisUtil.set(SMS_VCODE_MSG_KEY, tmpmsg, 30 * 60); // 缓存30分钟
            }
        }
        String msg = tmpmsg.replace("${vcode}", vcode);

        redisUtil.set(key, JSON.toJSONString(cache), request.getExpiresIn());
        LOG.info("短信验证码放入redis key:{},value:{}", key, JSON.toJSONString(cache));


    }

    @Override
    public boolean check(VcodeCheckRequest request) {
        if ("IGNORE_CHECKSMS".equals(request.getVcodeNamespace())) { // 快捷登入验证码命名空间后门
            return true;
        }
        if (StringUtil.equals(EnvTypeEnum.DEV.getCode(), prodEnv)
                || StringUtil.equals(EnvTypeEnum.STABLE.getCode(), prodEnv)) { // 对于开发环境和测试环境的短信后门
            if (allZero(request.getVcode())) {
                return true;
            }
        } else if (StringUtil.equals(EnvTypeEnum.RELEASE.getCode(), prodEnv)) {
            if (request.getAccountNo().equals("18017763788")) { // 正式环境手机号开后门
                return true;
            }
        }

        String key = KEY_PREFIX + request.getVcodeNamespace() + request.getAccountNo();
        LOG.info("短信验证码redis  key：{}", key);
        String cacheJson = (String) redisUtil.get(key);
        LOG.info("短信验证码redis  cacheJson：{}", cacheJson);
        if (StringUtil.isNotBlank(cacheJson)) {
            VcodeCache cache = JSON.parseObject(cacheJson, VcodeCache.class);
            if (LOG.isDebugEnabled()) {
                LOG.debug(
                        "{}缓存中验证码{}，参数验证码{}",
                        new Object[]{request.getAccountNo(), cache.getVcode(), request.getVcode()});
            }
            boolean b = cache.getVcode().equals(request.getVcode());
            // 只有输入成功才删除缓存
            if (b) {
                try {
                    redisUtil.del(key);
                } catch (Exception e) { // 缓存删除失败不影响业务
                    LOG.error("删除缓存{}失败", key);
                    LOG.error(e.getMessage(), e);
                }
            }
            return b;
        } else {
            LOG.info("{}验证码已不在缓存中", request.getAccountNo());
            return false;
        }

    }

    @Override
    public VcodeProcessTypeEnum getProcessType() {
        return VcodeProcessTypeEnum.MOBILE_SMS;
    }

    @Override
    public boolean checkNotDeleteKey(VcodeCheckRequest request) {
        if ("IGNORE_CHECKSMS".equals(request.getVcodeNamespace())) { // 快捷登入验证码命名空间后门
            return true;
        }
        if (StringUtil.equals(EnvTypeEnum.DEV.getCode(), prodEnv)
                || StringUtil.equals(EnvTypeEnum.STABLE.getCode(), prodEnv)) { // 对于开发环境和测试环境的短信后门
            if (allZero(request.getVcode())) {
                return true;
            }
        } else if (StringUtil.equals(EnvTypeEnum.RELEASE.getCode(), prodEnv)) {
            if (request.getAccountNo().equals("18017763788")) { // 正式环境手机号开后门
                return true;
            }
        }

        String key = KEY_PREFIX + request.getVcodeNamespace() + request.getAccountNo();
        String cacheJson = (String) redisUtil.get(key);
        if (StringUtil.isNotBlank(cacheJson)) {
            VcodeCache cache = JSON.parseObject(cacheJson, VcodeCache.class);
            if (LOG.isDebugEnabled()) {
                LOG.debug(
                        "{}缓存中验证码{}，参数验证码{}",
                        request.getAccountNo(), cache.getVcode(), request.getVcode());
            }
            //这里不删除key，直接返回
            return cache.getVcode().equals(request.getVcode());
        } else {
            LOG.info("{}验证码已不在缓存中", request.getAccountNo());
            return false;
        }

    }

    /**
     * 判断字符串都是0，为后门服务
     */
    private boolean allZero(String vcode) {
        for (char c : vcode.toCharArray()) {
            if (c != '0') {
                return false;
            }
        }
        return true;
    }
}
